#ifndef FUNCTIONAL_H
#define FUNCTIONAL_H

#include <functional>

namespace Tvimeg
{
	template<class S, class T, class A>
	class BindT : public std::unary_function<T, S>
	{
	public:
		BindT(A& objectIn, S (A::*methodIn)(T))
			:	method(methodIn), object(objectIn)
		{
		}

		S operator()(T value) const
		{
			return (object.*method)(value);
		}

	private:
		S (A::*method)(T);
		A& object;
	};

	template<class S, class T, class A>
	BindT<S, T, A> Bind(A& object, S (A::*method)(T))
	{
		return BindT<S, T, A>(object, method);
	}

	template<class S, class T, class A>
	BindT<S, T, const A> Bind(const A& object, S (A::*method)(T) const)
	{
		return BindT<S, T, const A>(object, method);
	}

	template<class S, class T, class A, class B>
	class BindParameterT : public std::binary_function<T, B, S>
	{
	public:
		BindParameterT(A& objectIn, S (A::*methodIn)(T, B), B arg2In)
			:	method(methodIn), object(objectIn), arg2(arg2In)
		{
		}

		S operator()(T value) const
		{
			return (object.*method)(value, arg2);
		}

	private:
		S (A::*method)(T, B);
		A& object;
		B arg2;
	};

	template<class S, class T, class A, class B>
	BindParameterT<S, T, A, B> Bind(A& object, S (A::*method)(T, B), B arg2)
	{
		return BindParameterT<S, T, A, B>(object, method, arg2);
	}

	template<class S, class T, class A, class B>
	BindParameterT<S, T, const A, B> Bind(const A& object, S (A::*method)(T, B) const, B arg2)
	{
		return BindParameterT<S, T, const A, B>(object, method, arg2);
	}

	template<class S, class T, class A, class B>
	BindParameterT<S, T, A, B&> Bind(A& object, S (A::*method)(T, B&), B& arg2)
	{
		return BindParameterT<S, T, A, B&>(object, method, arg2);
	}

	template<class S, class T, class A, class B>
	BindParameterT<S, T, const A, B&> Bind(const A& object, S (A::*method)(T, B&) const, B& arg2)
	{
		return BindParameterT<S, T, const A, B&>(object, method, arg2);
	}
}

#endif // FUNCTIONAL_H
